package com.ruixin.config;

import com.ruixin.annotation.BeanScan;
import com.ruixin.annotation.Parser;
import com.ruixin.base.BaseParser;
import com.ruixin.base.BaseTryCatch;
import com.ruixin.base.exception.BaseException;
import com.ruixin.base.factory.Factory;
import com.ruixin.base.proxy.ProxyHelper;
import com.ruixin.base.util.BeanUtil;
import com.ruixin.base.util.StringUtil;
import com.ruixin.bean.BeanObject;
import com.ruixin.parser.AnnotationParser;
import com.ruixin.parser.ClassParser;
import com.sun.istack.internal.NotNull;

import java.io.*;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.*;

/**
 * Created by Ruixin
 * Description:Applicaiton上下文
 */
public class ApplicationContext {

    //环境
    private Environment environment;

    //bean工厂
    private Factory<String, BeanObject> beanFactory = new Factory();
    //存储class/beanName
    private Factory<Class, String> beanNameFactory = new Factory();

    //注解解释工厂
    private Factory<Class<? extends Annotation>, BaseParser<ApplicationContext>> annotationParserFactory = new Factory<>();

    //Class扫描类
    private ClassLoader classLoader = new ClassLoader();

    //application监听类
    private List<ApplicationListener> applicationListeners = new ArrayList<>();

    //头文件
    private File bannerFile;

    public void setBeanFactory(Factory<String, BeanObject> beanFactory) {
        this.beanFactory = beanFactory;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Environment getEnvironment() {
        return environment;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    public Factory<String, BeanObject> getBeanFactory() {
        return beanFactory;
    }

    public Factory<Class<? extends Annotation>, BaseParser<ApplicationContext>> getAnnotationParserFactory() {
        return annotationParserFactory;
    }

    public void setAnnotationParserFactory(Factory<Class<? extends Annotation>, BaseParser<ApplicationContext>> annotationParserFactory) {
        this.annotationParserFactory = annotationParserFactory;
    }

    public ApplicationContext(Environment environment) throws BaseException {
        this.environment = environment;
    }

    /**
     * 获取Bean
     * @param beanName
     * @return
     */
    public Object getBean(String beanName){
        BeanObject beanObject = beanFactory.get(beanName);
        if(beanObject == null){
            return null;
        }
        return beanObject.getBean();
    }

    /**
     * 获取Bean
     * @param clz
     * @return
     */
    public <T> T getBean(Class<T> clz) throws BaseException {
        String beanName = this.beanNameFactory.get(clz);
        if(StringUtil.isBlackOrNull(beanName)){
            return null;
        }
        return clz.cast(this.getBean(beanName));
    }

    /**
     * 添加Bean
     * @param beanName
     * @param bean
     * @throws BaseException
     */
    public void addBean(@NotNull String beanName,@NotNull Object bean) throws BaseException {
        if(this.beanFactory.containsKey(beanName)){
            throw new BaseException("Bean[name="+beanName+"]已存在");
        }
        BeanObject beanObject = new BeanObject(beanName,bean);
        this.beanFactory.put(beanName,beanObject);
        this.beanNameFactory.put(beanObject.getBeanClass(),beanName);
    }

    /**
     * 通过注解获取解释器
     * @param annotation
     * @return
     */
    public BaseParser<ApplicationContext> getAnnotationParser(Class<? extends Annotation> annotation) throws BaseException {
        if(this.annotationParserFactory.containsKey(annotation)){
            return this.annotationParserFactory.get(annotation);
        }
        List<Annotation> annotations = BeanUtil.getAnnotations(annotation);
        for (Annotation anno:annotations){
            if(this.annotationParserFactory.containsKey(anno.annotationType())){
                return this.annotationParserFactory.get(anno.annotationType());
            }
        }
        return new BaseParser<>(this,annotation);
    }

    /**
     * 添加注解解释类
     * @param annotation
     * @param parser
     */
    public void addAnnotationParser(Class<? extends Annotation> annotation,BaseParser<ApplicationContext> parser){
        if(this.annotationParserFactory.containsKey(annotation)){
            BaseParser<ApplicationContext> baseParser = this.annotationParserFactory.get(annotation);
            if(baseParser.getClass()==parser.getClass()||parser.getClass().isAssignableFrom(baseParser.getClass())){
                return;
            }
        }
        this.annotationParserFactory.put(annotation,parser);
    }

    /**
     * 通过配置类加载
     * @param clz
     * @return
     * @throws BaseException
     */
    public static ApplicationContext builder(@NotNull Class<?> clz) throws BaseException {
        BeanScan beanScan = BeanUtil.getAnnotation(clz, BeanScan.class);
        if(beanScan!=null){
            String[] beanPackage = beanScan.beanPackage();
            String configFile = beanScan.configFile();
            String packs = StringUtil.join(beanPackage, ",");
            Environment environment = new Environment(configFile,packs);
            ApplicationContext applicationContext = new ApplicationContext(environment);
            applicationContext.load();
            return applicationContext;
        }else {
            throw new BaseException(clz.getName()+"类中找不到BeanScan类型注解");
        }
    }

    /**
     * 配置文件加载
     * @param configFile
     * @return
     * @throws BaseException
     */
    public static ApplicationContext builder(String configFile) throws BaseException {
        Environment environment = new Environment(configFile);
        ApplicationContext applicationContext = new ApplicationContext(environment);
        applicationContext.load();
        return applicationContext;
    }

    /**
     * 加载监听器
     * @throws BaseException
     */
    public void initApplicationListener() throws BaseException {
        BaseTryCatch.process(()->{
            Set<Class<ApplicationListener>> applicationListenerClasses = this.classLoader.getApplicationListenerClasses();
            for (Class<ApplicationListener> applicationListenerClass : applicationListenerClasses) {
                ApplicationListener applicationListener = BeanUtil.newInstance(applicationListenerClass);
                this.applicationListeners.add(applicationListener);
            }
        });
    }

    /**
     * 加载
     * @throws BaseException
     */
    protected void load() throws BaseException {
        //开始加载类
        classLoader.load(this.environment.getBeanPackage());
        //加载监听器
        initApplicationListener();
        //加载前事件
        for (ApplicationListener applicationListener : this.applicationListeners) {
            applicationListener.before(this);
        }
        this.preload();
        this.loading();
        //加载后事件
        for (ApplicationListener applicationListener : this.applicationListeners) {
            applicationListener.after(this);
        }
    }

    /**
     * 加载前事件
     * @throws BaseException
     */
    private void preload() throws BaseException {
        showBanner();
    }

    /**
     * 显示banner
     * @throws BaseException
     */
    private void showBanner() throws BaseException {
        BaseTryCatch.process(()->{
            if(this.bannerFile == null){
                Enumeration<URL> resources = ApplicationContext.class.getClassLoader().getResources("");
                while (resources.hasMoreElements()){
                    URL url = resources.nextElement();
                    if("file".equals(url.getProtocol())){
                        this.bannerFile = new File(url.getPath()+File.separator+BeanConstant.STR_BANNER);
                    }
                    if(this.bannerFile!=null&&this.bannerFile.exists()){
                        break;
                    }
                }
            }
            if(this.bannerFile != null&&this.bannerFile.exists()){
                Scanner sc = new Scanner(this.bannerFile);
                sc.useDelimiter("\\Z");
                System.out.println(sc.next());
            }
        });
    }

    /**
     * 加载Bean
     */
    protected void loading() throws BaseException {
        //设置默认的Parser注解解释
        AnnotationParser annotationParser = new AnnotationParser(this, Parser.class);
        this.annotationParserFactory.put(Parser.class,annotationParser);
        //设置默认的Class处理类
        ClassParser classParser = new ClassParser(this,null);
        classParser.init();
    }

    public File getBannerFile() {
        return bannerFile;
    }

    public void setBannerFile(File bannerFile) {
        this.bannerFile = bannerFile;
    }

    public List<ApplicationListener> getApplicationListeners() {
        return applicationListeners;
    }

    public void setApplicationListeners(List<ApplicationListener> applicationListeners) {
        this.applicationListeners = applicationListeners;
    }
}
